import Composite from '../core/Composite';
import Tick from '../core/Tick';
import { FINISHED } from '../constants';
import BaseNode from '../core/BaseNode';

/**
 * 从children中选取指定的去执行 
 */
export default abstract class Picker extends Composite {

    onTick(tick: Tick, ...args: any[]) {
        // 进行选取
        const result = this.pickArray(tick, ...args)
        // 检查pick的结果是否为空
        if (result.length === 0) {
            return this.defaultStatus();
        }
        // 当前数组
        const currentArray = [...result]
        const length = currentArray.length
        // 当前索引
        let currentIndex = 0
        // 对应Node
        let currentNode = this.pickNext(currentArray, currentIndex, length)
        while (currentNode) {
            const status = currentNode.execute(tick, ...args);
            // 判断是否为拦截
            if (this.isInterrupt(status)) {
                return status
            }
            // 判断是否[关注/不忽略]的状态
            if (!this.isIgnore(status)) {
                return status;
            }
            // 获取下一个
            currentNode = this.pickNext(currentArray, ++currentIndex, length);
        }
        // 返回默认的状态
        return this.defaultStatus();
    }

    /**
     * 获取遍历数组
     */
    protected pickArray(tick: Tick, ...args: any[]): BaseNode[] {
        return this.children
    }

    /**
     * 获取下个Node
     * 
     * @param array 可供选择的Node数组
     * @param current 当前Node索引
     * @param prev 上次选中的Node
     * @returns 本次选中的Node
     */
    protected pickNext(array: BaseNode[], current: number, length: number): BaseNode | null {
        if (current < 0 || current >= array.length) {
            return null
        }
        return array[current]
    }

    /**
     * 判断需要拦截的状态
     * 
     * @param status 当前状态
     * @returns 是否拦截 默认拦截[ERROR, FINISHED]
     */
    protected isInterrupt(status: number): boolean {
        return status >= FINISHED
    }


    // 默认的状态实现
    protected abstract defaultStatus(): number

    // 判断需要忽略的状态
    protected abstract isIgnore(status: number): boolean

};
